home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
MODEM.C
< prev
next >
Wrap
Text File
|
1993-10-09
|
11KB
|
491 lines
/* Automatic SLIP/PPP line dialer.
*
* Copyright 1991 Phil Karn, KA9Q
*
* Mar '91 Bill Simpson & Glenn McGregor
* completely re-written;
* human readable control file;
* includes wait for string, and speed sense;
* dials immediately when invoked.
* May '91 Bill Simpson
* re-ordered command line;
* allow dial only;
* allow inactivity timeout without ping.
* Sep '91 Bill Simpson
* Check known DTR & RSLD state for redial decision
* Mar '92 Phil Karn
* autosense modem control stuff removed
* Largely rewritten to do demand dialing
*/
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "config.h"
#ifdef MODEM
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "netuser.h"
#include "n8250.h"
#include "asy.h"
#include "tty.h"
#include "session.h"
#include "socket.h"
#include "cmdparse.h"
#include "devparam.h"
#include "icmp.h"
#include "files.h"
#include "trace.h"
#include "pktdrvr.h"
#include "modem.h"
#include "usock.h"
#include "commands.h"
#define MIN_INTERVAL 5L
unsigned Tiptimeout = 180; /* Default tip inactivity timeout (seconds) */
char TActive[] = "Tip or Dialer already active on %s\n";
static struct iface * near
check_if(char *s)
{
struct iface *ifp;
if((ifp = if_lookup(s)) == NULLIF) {
tprintf(Badif,s);
return NULLIF;
}
if(ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp) {
tprintf(Badasy,s);
return NULLIF;
}
return ifp;
}
static int
dodial_control(int argc,char **argv,void *p)
{
struct iface *ifp = p;
int param;
if(ifp->ioctl == NULL || (param = devparam(argv[1])) == -1) {
return -1;
}
(*ifp->ioctl)(ifp,param,TRUE,atol(argv[2]));
return 0;
}
static int
dodial_send(int argc,char **argv,void *p)
{
struct iface *ifp = p;
struct mbuf *bp;
if(argc > 2) {
/* Send characters with inter-character delay
* (for dealing with prehistoric Micom switches that
* can't take back-to-back characters...yes, they
* still exist.)
*/
char *cp;
int32 cdelay = atol(argv[2]);
for(cp = argv[1]; *cp != '\0'; cp++) {
bp = qdata(cp,1);
enqueue(&Asy[ifp->dev].sndq,bp);
/* asy_send(ifp->dev,bp); */
pause(cdelay);
}
} else {
bp = qdata(argv[1],strlen(argv[1]));
dump(ifp,IF_TRACE_OUT,-1,bp);
enqueue(&Asy[ifp->dev].sndq,bp);
/* asy_send(ifp->dev,bp); */
}
return 0;
}
static int
dodial_speed(int argc,char **argv,void *p)
{
struct iface *ifp = p;
return asy_speed(ifp->dev,(int16)atol(argv[1]));
}
static int
dodial_wait(int argc,char **argv,void *p)
{
struct iface *ifp = p;
int c = -1;
int32 timeout = atol(argv[1]);
if(!timeout) {
timeout = 10;
argc = 2;
}
alarm(timeout);
if(argc == 2) {
while((c = get_asy(ifp->dev)) != -1) {
/* usputc(Curproc->output,c); */
}
/* usflush(Curproc->output); */
alarm(0);
return 0;
} else {
char *cp = argv[2];
while(*cp != '\0' && (c = get_asy(ifp->dev)) != -1) {
/* usputc(Curproc->output,c); */
if(*cp++ != c) {
cp = argv[2];
}
}
/* usflush(Curproc->output); */
if(argc > 3) {
if(stricmp(argv[3],"speed") == 0 ) {
int16 speed = 0;
while((c = get_asy(ifp->dev)) != -1) {
/* usputc(Curproc->output,c); */
if(isdigit(c)) {
speed *= 10;
speed += c - '0';
} else {
alarm(0);
return asy_speed(ifp->dev,speed);
}
}
/* usflush(Curproc->output); */
} else {
alarm(0);
return -1;
}
}
}
alarm(0);
return (c == -1);
}
/* execute dialer commands
* returns: -1 fatal error, 0 OK, 1 try again
*/
int
redial(struct asy *asyp,int flag)
{
char inbuf[MAXPATH], intmp[MAXPATH], *file = flag ? asyp->actfile : asyp->dropfile;
FILE *fp;
int result = 0, (*rawsave) __ARGS((struct iface *,struct mbuf *));
static char Dial[] = "\nDialing on %s%s\n";
static struct cmds dial_cmds[] = {
{"control", dodial_control, 0, 2, "control up|down"},
{"send", dodial_send, 0, 2, "send \"string\" [<msecs>]"},
{"speed", dodial_speed, 0, 2, "speed <bps>"},
{"wait", dodial_wait, 0, 2, "wait <msecs> [\"string\" [speed]]"},
{NULLCHAR, NULLFP, 0, 0, "Unknown command"},
};
if((fp = Fopen(file,READ_TEXT,0,1)) == NULLFILE) {
return -1;
}
/* Save output handler and temporarily redirect output to null */
if(asyp->iface->raw == bitbucket) {
tprintf(TActive,asyp->iface->name);
return -1;
}
tprintf(Dial,asyp->iface->name,"");
/* Save output handler and temporarily redirect output to null */
rawsave = asyp->iface->raw;
asyp->iface->raw = bitbucket;
/* Suspend the packet input driver. Note that the transmit driver
* is left running since we use it to send buffers to the line.
*/
suspend(asyp->iface->proc);
while(fgets(inbuf,MAXPATH,fp) != NULLCHAR) {
rip(inbuf);
strcpy(intmp,inbuf);
log(-1,9984,"%s: %s",asyp->iface->name,intmp);
if((result = cmdparse(dial_cmds,inbuf,asyp->iface)) != 0) {
tprintf("ERROR line: %s\n",intmp);
break;
}
}
Fclose(fp);
if(result == 0) {
asyp->iface->lastsent = asyp->iface->lastrecv = secclock();
}
asyp->iface->raw = rawsave;
resume(asyp->iface->proc);
tprintf(Dial,asyp->iface->name," complete");
return result;
}
static void
dropit(int i,void *p,void *u)
{
struct iface *ifp = p;
struct asy *ap = &Asy[ifp->dev];
if(ap->msr & MSR_RLSD) {
ap->localdrops++;
redial(ap,0); /* Drop only if still up */
}
}
/* Called when idle line timer expires -- executes script to drop line */
static void
dropline(void *p)
{
/* Fork this off to prevent wedging the timer task */
newproc("dropit",768,dropit,0,p,NULL,0);
}
/* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
* <iface> must be asy type
* <filename> contains commands which are executed.
* missing: kill outstanding dialer.
* <seconds> interval to check for activity on <iface>.
* <pings> number of missed pings before redial.
* <hostid> interface to ping.
*/
int
dodial(int argc,char **argv,void *p)
{
struct iface *ifp;
struct asy *ap;
int32 timeout;
if((ifp = check_if(argv[1])) == NULLIF) {
return 1;
}
ap = &Asy[ifp->dev];
if(!ap->rlsd){
tputs("Must set 'r' flag at attach time\n");
return -1;
}
if(argc < 3) {
tprintf("%s: %s, idle timer %ld/%ld secs\n",
ifp->name,
(ap->msr & MSR_RLSD) ? "UP" : "DOWN",
read_timer(&ap->idle)/1000L,
dur_timer(&ap->idle)/1000L);
if(ap->actfile != NULLCHAR) {
tprintf("Up script: %s\n",ap->actfile);
}
if(ap->dropfile != NULLCHAR) {
tprintf("Down script: %s\n",ap->dropfile);
}
tprintf("Calls originated/timed out %ld/%ld, Carrier up/down transitions %ld/%ld\n",
ap->originates,ap->localdrops,ap->answers,ap->remdrops);
return 0;
}
if((timeout = atol(argv[2]) * 1000L) != 0 && argc < 5) {
tputs("Usage: dial <iface> <timeout> <raisefile> <dropfile>\n"
" dial <iface> 0\n");
return -1;
}
stop_timer(&ap->idle);
set_timer(&ap->idle,0);
if(ap->actfile != NULLCHAR) {
xfree(ap->actfile);
ap->actfile = NULLCHAR;
}
if(ap->dropfile != NULLCHAR){
xfree(ap->dropfile);
ap->dropfile = NULLCHAR;
}
if(timeout != 0) {
ap->actfile = mxallocw(MAXPATH);
sprintf(ap->actfile,"%s/%s",EtcRoot,argv[3]);
ap->dropfile = mxallocw(MAXPATH);
sprintf(ap->dropfile,"%s/%s",EtcRoot,argv[4]);
ap->idle.func = dropline;
ap->idle.arg = ifp;
set_timer(&ap->idle,timeout);
start_timer(&ap->idle);
}
return 0;
}
/* Input process */
void
tip_in(int dev,void *n1,void *n2)
{
struct tipcb *tip = n1;
struct mbuf *bp;
char *buf[2], line[LINELEN];
int c, pos = 0;
while((c = get_asy(dev)) != -1){
int ret = 0;
Asy[dev].iface->lastrecv = secclock();
if(tip->echo == WONT) {
switch(c) {
case 18: /* CTRL-R */
bp = pushdown(qdata(line,pos),4);
memcpy(bp->data,"^R\r\n",4);
ret = 1;
break;
case 0x7f: /* DEL */
case '\b':
bp = NULLBUF;
if(pos) {
--pos;
bp = qdata("\b \b",3);
}
ret = 1;
break;
case '\r':
c = '\n'; /* CR => NL */
case '\n':
bp = qdata("\r\n",2);
break;
default:
bp = pushdown(NULLBUF,1);
*bp->data = c;
break;
}
enqueue(&Asy[dev].sndq,bp);
/* asy_send(dev,bp); */
tip->iface->lastsent = secclock();
if(ret) {
continue;
}
}
line[pos++] = c;
if(pos == LINELEN - 1 || tip->echo == WILL || c == '\n') {
line[pos] = '\0';
pos = 0;
usputs(tip->s,line);
}
}
/* get_asy() failed, terminate */
close_s(tip->s);
tip->in = tip->proc;
tip->proc = Curproc;
buf[1] = Asy[dev].iface->name;
tip0(2,buf,NULL);
}
/* Output process, DTE version */
static void
tip_out(int dev,void *n1,void *n2)
{
int c;
while((c = recvchar(Curproc->input)) != EOF) {
struct mbuf *bp = pushdown(NULLBUF,1);
if(c != '\n') {
*bp->data = c;
} else {
*bp->data = '\r';
}
enqueue(&Asy[dev].sndq,bp);
/* asy_send(dev,bp); */
Asy[dev].iface->lastsent = secclock();
}
}
/* Execute user tip command */
int
dotip(int argc,char **argv,void *p)
{
struct session *sp;
struct iface *ifp;
char *ifn;
int c, (*rawsave) __ARGS((struct iface *,struct mbuf *));
if((ifp = check_if(argv[1])) == NULLIF) {
return -1;
}
if(ifp->raw == bitbucket) {
tprintf(TActive,argv[1]);
return -1;
}
/* Allocate a session descriptor */
if((sp = newsession(argv[1],TIP,SWAP)) == NULLSESSION){
tputs(Nosess);
keywait(NULLCHAR,1);
return 1;
}
/* Save output handler and temporarily redirect output to null */
rawsave = ifp->raw;
ifp->raw = bitbucket;
/* Suspend the packet input driver. Note that the transmit driver
* is left running since we use it to send buffers to the line.
*/
suspend(ifp->proc);
/* Put tty into raw mode */
sp->ttystate.echo = sp->ttystate.edit = 0;
sockmode(sp->output,SOCK_BINARY);
/* Now fork into two paths, one rx, one tx */
ifn = if_name(ifp," tip out");
sp->proc1 = newproc(ifn,256,tip_out,ifp->dev,NULL,NULL,0);
xfree(ifn);
ifn = if_name(ifp," tip in");
sprintf(Curproc->name,"%.16s",ifn);
xfree(ifn);
/* bring the line up (just in case) */
if(ifp->ioctl != NULL) {
(*ifp->ioctl)(ifp,PARAM_UP,TRUE,0);
}
while((c = get_asy(ifp->dev)) != -1) {
usputc(Curproc->output,c);
}
usflush(Curproc->output);
killproc(sp->proc1);
sp->proc1 = NULLPROC;
ifp->raw = rawsave;
resume(ifp->proc);
keywait(NULLCHAR,1);
freesession(sp);
return 0;
}
void
tipidle(void *t)
{
static char *msg = "You have been idle too long. Please hang up.\r\n";
struct tipcb *tip = (struct tipcb *)t;
if(secclock() - tip->iface->lastrecv < Tiptimeout) {
set_timer(&tip->timer,(Tiptimeout-secclock() * tip->iface->lastrecv) * 1000);
start_timer(&tip->timer);
return;
}
enqueue(&Asy[tip->iface->dev].sndq,qdata(msg,strlen(msg)));
/* asy_send(tip->iface->dev,qdata(msg,strlen(msg))); */
tip->iface->lastsent = secclock();
close_s(tip->s);
}
#endif /* MODEM */